/*
 * inotify-sync - a simple file synchronizer and file system watcher
 * Copyright (C) 2010-2011, inotify-sync developers and inotify-sync contributors
 * Copyright (C) 2010-2011, Cohesion Network Security Studio
 *
 * inotify-sync is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * inotify-sync is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with inotify-sync; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <getopt.h>
#include <map>
#include <string>

#include "Inotify.h"
#include "EventHandler.h"
#include "ProfileXml.h"
#include "Profile.h"
#include "ConfigXml.h"
#include "Config.h"
#include "Syncer.h"
#include "Converter.h"

Converter Conv;

void help();
void all(ProfileXml *p_profile_xml);
void del(ProfileXml *p_profile_xml,const char *profile_name);
void list(ProfileXml *p_profile_xml,const char *profile_name);

int main(int argc,char *argv[])
{
//读取配置
	Config config=Config();
	ConfigXml config_xml=ConfigXml();
	config_xml.get_config(config);
//使用配置中的profile_path字段来初始化ProfileXml对象
	ProfileXml profile_xml=ProfileXml(config.get_profile_path());

//如果无任何参数则打印帮助信息
	if(argc==1)
	{
		help();
		return 0;
	}

//设置长选项
	struct option longopts[]=
	{
		{"all",no_argument,NULL,'a'},
		{"delete",required_argument,NULL,'d'},
		{"list",required_argument,NULL,'l'},
		{"time",required_argument,NULL,'t'},
		{"help",no_argument,NULL,'h'}
	};

	std::map<time_t,std::string> r_time_map;
//循环使用getopt_long判断参数
	int ch;
	while((ch=getopt_long(argc,argv,"ad:l:t:h",longopts,NULL))!=-1)
	{
		switch(ch)
		{
		case 'a':
			all(&profile_xml);
			return 0;
		case 'd':
			del(&profile_xml,optarg);
			return 0;
		case 'l':
			list(&profile_xml,optarg);
			return 0;
		case 't':
			time_t r_time;
			r_time=Conv.conv<time_t>(string(optarg));
			r_time_map.insert(std::make_pair(r_time,argv[optind]));
			break;
		case 'h':
		case '?':
		//如果有错误的参数，会打印错误信息
			help();
			return 0;
		}
	}
	std::map<pid_t,std::string> pid_map;
	for(int i=optind;i<argc;i++)
	{
		pid_t pid;
		if((pid=fork())<0)
		{
			perror("fork error");
		}
		else if(pid==0)
		{
			Profile profile=Profile();
			profile.set_profile_name(argv[i]);
			try
			{
				if(!profile_xml.get_profile(profile))
					throw Error(0,E_PROFNOTEXIST);
			}
			catch(Error& error)
			{
				error.print_error_detail();
				exit(error.get_error_id());
			}
	
			Inotify inotify=Inotify(profile);
			EventHandler event_handler=EventHandler(profile);
			inotify.get_event_handler(&event_handler);
			event_handler.get_inotify(&inotify);
	
			std::map<time_t,std::string>::iterator pos;
			time_t r_time=0;
			for(pos=r_time_map.begin();pos!=r_time_map.end();pos++)
			{
				if(pos->second==argv[i])
				{
					r_time=pos->first;
					break;
				}
			}
			inotify.monitor(r_time);
			
			exit(0);
		}
		pid_map.insert(std::make_pair(pid,argv[i]));
	}
	while(pid_map.size()!=0)
	{
		std::map<pid_t,std::string>::iterator pos;
		for(pos=pid_map.begin();pos!=pid_map.end();pos++)
		{
			int exit_stat=0;
			if(waitpid(pos->first,&exit_stat,WNOHANG)==pos->first)
			{
				if(WIFEXITED(exit_stat))
				{
					printf("inotify-sync: profile \"%s\" is exited with status %d\n",
						(pos->second).c_str(),
						WEXITSTATUS(exit_stat));
					printf("pid=%d\n",pos->first);
				}
				pid_map.erase(pos);
			}
		}
	}
	return 0;
}

void help()
{
	printf("Usage: inotify-sync [OPTION...] [PROFILE...]\n");
	printf("a simple file synchronizer and file system watcher.\n");
	printf("\n");
	printf("Options:\n");
	printf("  -a, --all\t\t\tPrint PROFILE list.\n");
	printf("  -d PROFILE, --delete PROFILE\tDelete PROFILE.\n");
	printf("  -l PROFILE, --list PROFILE\tList PROFILE detail.\n");
	printf("  -t TIME, --time TIME\t\tRun for TIME seconds, 0 for unlimited.\n");
	printf("  -h, --help\t\t\tPrint this message and exit.\n");
}

void all(ProfileXml *p_profile_xml)
{
	vector<string> profile_list;
	p_profile_xml->get_profile_list(profile_list);
	if(profile_list.size()==0)
	{
		printf("There is no profile now!\n");
	}
	else
	{
		for(size_t i=0;i<profile_list.size();i++)
		{
			printf("Profile Name: %s\n",profile_list[i].c_str());
		}
	}
	return;
}

void del(ProfileXml *p_profile_xml,const char *profile_name)
{
	if(p_profile_xml->delete_profile(profile_name))
		printf("Profile \"%s\" delete success!\n",profile_name);
	else
		printf("No such a profile: %s\n",profile_name);
	return;
}

void list(ProfileXml *p_profile_xml,const char *profile_name)
{
	Profile profile=Profile();
	profile.set_profile_name(profile_name);
	if(p_profile_xml->get_profile(profile))
	{
		profile.print();
	}
	else
		printf("No such a profile:\t\t%s\n",profile_name);
	return;
}
